﻿using ArtMath.Attribute;
using ArtMath.Component.Interface;
using ArtMath.Component.Point;
using ArtMath.Converter;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Helper;
using ArtMath.PointCollection;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using ArtMath.CommonType;

namespace ArtMath.Component.Line
{
    /// <summary>
    /// 射线基类
    /// </summary>
    [Serializable]
    public abstract class RayBase : StraightLineBase, IDirectedAngle
    {
        double dirAngle;//, rotAngle;
        PropertyDisplayer dirAngleDisplayer;
        //Ray ske = new Ray(), pske = new Ray();
        List<KeyValuePair<PointD, double>> track = new List<KeyValuePair<PointD, double>>();
        public RayBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            DirectedAngleDisplayer = new PropertyDisplayer(this, "DirectedAngle");
        }
        public override PointCollectionsManager Skeleton
        {
            get
            {
                return new PointCollectionsManager(new Ray(SourcePoint.ToPointD(), DirectedAngle));
            }
        }
        public override PointCollectionsManager PSkeleton
        {
            get
            {
                return new PointCollectionsManager(new Ray(SourcePoint.Pxy, Pad.RadToPRad(DirectedAngle)));
            }
        }
        public override PointCollectionsManager NewSkeleton
        {
            get
            {
                return new PointCollectionsManager(new Ray(SourcePoint.NewXY, NewDirectedAngle));
            }
        }
        public override PointCollectionsManager NewPSkeleton
        {
            get
            {
                return new PointCollectionsManager(new Ray(SourcePoint.NewPxy, Pad.RadToPRad(NewDirectedAngle)));
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName(null, "Source", "Point")]
        public PointBase SourcePoint
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        [MultilingualCategory("Parameter"), MultilingualDisplayName("DirectedAngle"), TypeConverter(typeof(IntelliAngleConverter)), ReadOnly(true)]
        public double DirectedAngle
        {
            get { return dirAngle; }
            set
            {
                //rotAngle = Utility.GetRotatedAngle(dirAngle.GetUnitVector(), value.GetUnitVector());
                dirAngle = value;
                if (ToolType != ToolTypeName.ldsx)
                {
                    Slope = Math.Tan(dirAngle);
                }
            }
        }
        [MultilingualCategory(null, "Sketchpad", "Display"), MultilingualDisplayName(null, "DirectedAngle", "Displayer")]
        public PropertyDisplayer DirectedAngleDisplayer
        {
            get { return dirAngleDisplayer; }
            set { dirAngleDisplayer = value; }
        }
        public override double ArrivalAngle
        {
            get
            {
                return NewDirectedAngle;
            }
        }
        //[Browsable(false)]
        //public virtual double NewPDirectedAngle
        //{
        //    get
        //    {
        //        return Pad.RadToPRad(DirectedAngle);
        //    }
        //}

        [Browsable(false)]
        public virtual double NewDirectedAngle
        {
            get
            {
                return DirectedAngle;
            }
        }
        public override double Slope
        {
            get
            {
                return base.Slope;
            }

            set
            {
                base.Slope = value;
                if (ToolType != ToolTypeName.ldsx)
                {
                    PSlope = Pad.kToPk(Slope);
                }
            }
        }
        public override double NewSlope
        {
            get
            {
                return Math.Tan(NewDirectedAngle);
            }
        }
        public override double NewPSlope
        {
            get
            {
                return Pad.kToPk(NewSlope);
            }
        }
        //protected override PointD GetAbsorbedPoint(PointD PLocation, bool getNew = false)
        //{
        //    if (getNew)
        //    {
        //        if (Utility.ScalarProduct(new PointD(Math.Cos(NewPDirectedAngle), Math.Sin(NewPDirectedAngle)), PLocation - SourcePoint.NewPxy) < 0)
        //        {
        //            return SourcePoint.NewPxy;
        //        }
        //    }
        //    else
        //    {
        //        if (Utility.ScalarProduct(DirectedAngle.PUnitVector, PLocation - SourcePoint.Pxy) < 0)
        //        {
        //            return SourcePoint.Pxy;
        //        }
        //    }
        //    return base.GetAbsorbedPoint(PLocation, getNew);
        //}
        public override void RefreshPropertyDisplayersText()
        {
            DirectedAngleDisplayer.RefreshText();
            base.RefreshPropertyDisplayersText();
        }
        public override void RefreshPropertyDisplayersLocation()
        {
            DirectedAngleDisplayer.RefreshLocation();
            base.RefreshPropertyDisplayersLocation();
        }
        public override void PaintProperties(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible)
            {
                DirectedAngleDisplayer.Paint(gra);
            }
            base.PaintProperties(gra);
        }
        public override void AddTracks()
        {
            track.Add(new KeyValuePair<PointD, double>(SourcePoint.Pxy, Pad.DegToPDeg(DirectedAngle * Core.Helper.Angle.RToD)));
        }
        public override void ClearTracks()
        {
            track.Clear();
            base.ClearTracks();
        }
        //public override void SetPoint(int index, RPoint value)
        //{
        //    base.SetPoint(index, value);
        //    if (value != null)
        //    {
        //        switch (index)
        //        {
        //            case 0:
        //                ske.SourcePoint = value.ToPointD();
        //                pske.SourcePoint = value.Pxy;
        //                break;
        //        }
        //    }
        //}
        //public override PointD SlideDestination(PointD currentLocation, double length, out bool reverse)
        //{
        //    return NewSkeleton.SlideDestination(currentLocation, length, out reverse);
        //    PointD tmp = base.SlideDestination(currentLocation, length, out reverse);
        //    if (Utility.ScalarProduct(tmp - SourcePoint.NewXY, NewDirectedAngle.GetUnitVector()) < 0)
        //    {
        //        tmp = SourcePoint.NewXY.Offset(NewDirectedAngle, tmp.DistanceTo(SourcePoint.NewXY));
        //        reverse = true;
        //    }
        //    return tmp;
        //}
        public override void CheckInRegion(RectangleD rect)
        {
            SetInPicker(rect.IntersectRay(SourcePoint.Pxy, Pad.RadToPRad(DirectedAngle)));
            base.CheckInRegion(rect);
        }
        public override void Paint(Graphics gra)
        {
            if (ObjectState == ObjectState.Normal && Visible && IsCreationCompleted)
            {
                gra.DrawRay(Pad, LinePen, SourcePoint.Pxy, Pad.DegToPDeg(DirectedAngle * Core.Helper.Angle.RToD));
            }
            base.Paint(gra);
        }
        public override bool CanDrawVirtual
        {
            get
            {
                return SourcePoint != null;
            }
        }
        //[Browsable(false)]
        //public double RotatedAngle
        //{
        //    get { return rotAngle; }
        //}
        //[Browsable(false)]
        //public virtual bool IsClockwiselyMove
        //{
        //    get
        //    {
        //        return Utility.CrossProduct(DirectedAngle.GetUnitVector(), NewDirectedAngle.GetUnitVector()) <= 0;
        //    }
        //}
        public override PropertyDisplayer[] PropertyDisplayersCheckNearBy(PointD Plocation)
        {
            List<PropertyDisplayer> res = new List<PropertyDisplayer>(base.PropertyDisplayersCheckNearBy(Plocation));
            if (DirectedAngleDisplayer.InRegion(Plocation))
            {
                res.Add(DirectedAngleDisplayer);
            }
            return res.ToArray();
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            if (CanDrawVirtual)
            {
                gra.DrawRay(Pad, SourcePoint.Pxy, Pad.DegToPDeg(DirectedAngle * Core.Helper.Angle.RToD));
            }
            base.PaintVirtualObjects(gra);
        }
        public override void ComponentChanged(ShapeBase component)
        {
            DirectedAngle = NewDirectedAngle;
            base.ComponentChanged(component);
        }
        public override void PaintTrack(Graphics gra)
        {
            if (ShowTrack_)
            {
                //PointD len;
                //SizeD size = Pad.PSize;
                //Pen p = TrackPen;
                for (int i = 0; i < track.Count; i++)
                {
                    //gra.TranslateTransform((float)item.Key.X, (float)item.Key.Y);
                    //gra.RotateTransform((float)item.Value);
                    //len = Utility.CalcLength(PointD.FromPoint(Pad.PxyToMouseLocation(item.Key)) / Pad.Zoom.ToPointD(),
                    //    size, Angle.DegreeRound - item.Value);
                    //gra.DrawLine(p, 0, 0, (float)len.Y, 0);
                    //gra.RotateTransform((float)-item.Value);
                    //gra.TranslateTransform((float)-item.Key.X, (float)-item.Key.Y);
                    gra.DrawRay(Pad, TrackPen, track[i].Key, track[i].Value);
                }
            }
            base.PaintTrack(gra);
        }
    }
}
